using NHibernate;
using Rubikev.Common.Data;
using Rubikev.Common.DependencyInjection;
using ISession = NHibernate.ISession;

namespace Rubikev.NHibernate
{
   /// <summary>
   /// Registers the NHibernate SessionFactory to a singleton scope and Session to HttpContext scope
   /// </summary>
   public class WebRegister : IRegister
   {
      private readonly ITypeRegister typeRegister;
      private readonly ITypeProvider typeProvider;

      public WebRegister(ITypeRegister typeRegister, ITypeProvider typeProvider)
      {
         this.typeRegister = typeRegister;
         this.typeProvider = typeProvider;
      }

      /// <summary>
      /// Registers the NHibernate SessionFactory to a singleton scope and Session to HttpContext scope
      /// </summary>
      public void Register()
      {
         // Use the SessionFactoryFactory for creating the ISessionFactory, which will be configured to a singleton by default
         typeRegister.RegisterType(SessionFactoryFactory.CreateSessionFactory);

         // Use the configured ISessionFactory to provide NH ISession instances, creating a new one each time - the common ISession should be scoped as the application requires
         typeRegister.RegisterType(CreateSession, LifetimeScope.Instance);

         // Set up the generic IDAO
         typeRegister.RegisterType(typeof (IDao<>), typeof (Dao<>), LifetimeScope.Instance);
      }

      /// <summary>
      /// Creates the session from the session factory, and begins a transaction
      /// </summary>
      /// <returns></returns>
      private ISession CreateSession()
      {
         ISession session = typeProvider.GetInstance<ISessionFactory>().OpenSession();

         try
         {
            session.BeginTransaction();
         }
         catch
         {
            session.Close();
            throw;
         }

         return session;
      }
   }
}